/*******************************************************************************
 * Copyright (c) 2007 University of Oslo.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     University of Oslo - initial API and implementation
 *******************************************************************************/

package com.cea.papyrus.diagram.sequence.sedi.edit.handlers;

import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.gef.EditPolicy;
import org.eclipse.gef.GraphicalEditPart;
import org.eclipse.gef.commands.Command;
import org.eclipse.gef.requests.CreateRequest;
import org.eclipse.uml2.uml.CombinedFragment;
import org.eclipse.uml2.uml.InteractionOperand;

import com.cea.papyrus.core.utils.LookForElement;
import com.cea.papyrus.diagram.sequence.sedi.edit.command.AnalyseOwnerCommand;
import com.cea.papyrus.diagram.sequence.sedi.edit.command.DecideGuardBoundsCommand;
import com.cea.papyrus.diagram.sequence.sedi.edit.command.SelectPartCommand;
import com.cea.papyrus.diagram.sequence.sedi.model.command.CreateGraphicalElementCommand;
import com.cea.papyrus.diagram.sequence.sedi.model.command.CreateGuardCommand;
import com.cea.papyrus.diagram.sequence.sedi.model.command.diagram.SetBoundsHintCommand;
import com.cea.papyrus.diagram.sequence.sedi.model.util.ModelUtil;
import com.cea.papyrus.diagraminterchange2.di2.GraphElement;
import com.cea.papyrus.diagraminterchange2.di2.GraphNode;

/**
 * Handles creation of guards in interaction operands.
 * <p>
 * This handler is used from FrameLayoutPolicy.
 * </p>
 * 
 * @author frankd@ifi.uio.no
 */
public class GuardCreateHandler {

	public final EditPolicy hostPolicy;

	public GuardCreateHandler(final EditPolicy hostPolicy) {
		this.hostPolicy = hostPolicy;
	}

	@SuppressWarnings("unchecked")
	public Command[] getCreateCommands(final CreateRequest request,
			final Point suggestedLocation) {

		final GraphicalEditPart interactionEP = (GraphicalEditPart) hostPolicy
				.getHost();
		final GraphNode interactionView = (GraphNode) interactionEP.getModel();
		GraphElement diagram = LookForElement.getDiagram(interactionView);

		Point suggestedLocAbs = suggestedLocation.getCopy();
		interactionEP.getFigure().translateToParent(suggestedLocAbs);
		interactionEP.getFigure().getParent().translateToAbsolute(
				suggestedLocAbs);

		// Check if the current point is acceptable:
		// 1. the owner is an InteractionOperand, and
		// 2. it does not already have a guard

		final AnalyseOwnerCommand analyseOwnerCmd = new AnalyseOwnerCommand();
		analyseOwnerCmd.setAnyEditPart(interactionEP);
		analyseOwnerCmd.setDiagram(LookForElement.getDiagram(interactionView));
		analyseOwnerCmd.setLocation(suggestedLocAbs);
		analyseOwnerCmd.execute();
		if (!(analyseOwnerCmd.getOwner() instanceof InteractionOperand))
			return null;
		final InteractionOperand ownerOperand = (InteractionOperand) analyseOwnerCmd
				.getOwner();
		if (ownerOperand.getGuard() != null)
			return null;

		// DecideGuardBoundsCommand [SeDi]
		// Decide on suitable bounds
		// SetBoundsHintCommand [SeDi]
		// Register the decision made by the previous command as a hint
		// CreateGuardCommand [UML]
		// Creates the UML element and adds it to the interaction operand.
		// When the command is executed, a GraphicalElement will be
		// created in response to the notification. This creation will
		// consume the Bounds hint set previously

		final DecideGuardBoundsCommand analyseBoundsCmd = new DecideGuardBoundsCommand();
		analyseBoundsCmd.setAnyEditPart(interactionEP);
		analyseBoundsCmd.setDiagram(LookForElement.getDiagram(interactionView));
		analyseBoundsCmd.setHint(new Rectangle(suggestedLocAbs.x,
				suggestedLocAbs.y, 0, 0));
		analyseBoundsCmd.setOperand((InteractionOperand) analyseOwnerCmd
				.getOwner());

		final SetBoundsHintCommand boundsHint = new SetBoundsHintCommand();
		// glue: hint

		final CreateGuardCommand createCmd = new CreateGuardCommand();
		createCmd.setOperand(ownerOperand);

		final CreateGraphicalElementCommand createGECmd = new CreateGraphicalElementCommand();
		GraphElement parentGE = ModelUtil.getGraphElement(ownerOperand
				.getOwner(), diagram);
		createGECmd.setParentGE(parentGE);
		createGECmd.setAnyEditPart(hostPolicy.getHost());

		final SelectPartCommand selectCmd = new SelectPartCommand();
		selectCmd.setAnyEditPart(hostPolicy.getHost().getRoot());
		selectCmd.setSelectForEdit(true);

		final Command glue1 = new Command() {
			public void execute() {
				// convert to coords local to CF
				CombinedFragment ownerCF = (CombinedFragment) ownerOperand
						.getOwner();
				GraphNode cfView = ModelUtil.getGraphNode(ownerCF,
						LookForElement.getDiagram(interactionView));
				GraphicalEditPart cfEP = (GraphicalEditPart) interactionEP
						.getViewer().getEditPartRegistry().get(cfView);

				Rectangle bounds = analyseBoundsCmd.getPreferredBounds();
				cfEP.getFigure().translateToRelative(bounds);
				cfEP.getFigure().translateFromParent(bounds);
				boundsHint.setHint(bounds);
			}
		};

		final Command glue2 = new Command() {
			public void execute() {
				selectCmd.setTarget(createCmd.getConstraint());
				createGECmd.setElement(createCmd.getConstraint());
			}
		};

		return new Command[] { analyseBoundsCmd, glue1, boundsHint, createCmd,
				glue2, createGECmd, selectCmd };
	}
}
